package com.xiaoyu.tool.service.order;

import com.xiaoyu.tool.configuration.wx.WxPayProperty;
import com.xiaoyu.tool.entity.User.User;
import com.xiaoyu.tool.entity.User.UserAddress;
import com.xiaoyu.tool.entity.order.LineItem;
import com.xiaoyu.tool.entity.order.Order;
import com.xiaoyu.tool.entity.order.OrderAddress;
import com.xiaoyu.tool.entity.product.Product;
import com.xiaoyu.tool.enums.ResultEnum;
import com.xiaoyu.tool.enums.order.OrderPayType;
import com.xiaoyu.tool.enums.order.OrderStatus;
import com.xiaoyu.tool.enums.order.OrderType;
import com.xiaoyu.tool.exception.WechatAlipayToolException;
import com.xiaoyu.tool.messageQueue.sender.ExpireAndDeleteOrderSender;
import com.xiaoyu.tool.repository.order.LineItemRepository;
import com.xiaoyu.tool.repository.order.OrderAddressRepository;
import com.xiaoyu.tool.repository.order.OrderRepository;
import com.xiaoyu.tool.repository.product.ProductRepository;
import com.xiaoyu.tool.repository.user.UserAddressRepository;
import com.xiaoyu.tool.repository.user.UserRepository;
import com.xiaoyu.tool.response.order.OrderNewRequest;
import com.xiaoyu.tool.utils.DateUtils;
import com.xiaoyu.tool.utils.WebUtil;
import com.xiaoyu.tool.utils.pay.PayCommonUtil;
import com.xiaoyu.tool.utils.pay.WxPayUtil;
import com.xiaoyu.tool.utils.pay.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author xiaoyu on 2018/11/01
 */
@Slf4j
@Service
public class OrderService {

    private final UserRepository userRepository;

    private final OrderRepository orderRepository;

    private final OrderAddressRepository orderAddressRepository;

    private final UserAddressRepository userAddressRepository;

    private final LineItemService lineItemService;

    private final WxPayProperty wxPayProperty;

    private final LineItemRepository lineItemRepository;

    private final ProductRepository productRepository;

    private final ExpireAndDeleteOrderSender expireAndDeleteOrderSender;

    public OrderService(UserRepository userRepository, OrderRepository orderRepository, OrderAddressRepository orderAddressRepository, UserAddressRepository userAddressRepository, LineItemService lineItemService, WxPayProperty wxPayProperty, LineItemRepository lineItemRepository, ProductRepository productRepository, ExpireAndDeleteOrderSender expireAndDeleteOrderSender) {
        this.userRepository = userRepository;
        this.orderRepository = orderRepository;
        this.orderAddressRepository = orderAddressRepository;
        this.userAddressRepository = userAddressRepository;
        this.lineItemService = lineItemService;
        this.wxPayProperty = wxPayProperty;
        this.lineItemRepository = lineItemRepository;
        this.productRepository = productRepository;
        this.expireAndDeleteOrderSender = expireAndDeleteOrderSender;
    }
    /**
     * 运费
     * */
    @Value("${wx-pay.freightPrice}")
    private BigDecimal freightPrice;

    @Transactional
     
    public Order createOrder(OrderNewRequest orderNewRequest, String unionId) {
        User user = userRepository.findByUnionId(unionId);
        //1.创建订单详情
        Order order = new Order();
        order.setUserId(user.getId());
        order.setIsUseIntegral(orderNewRequest.getIsUseIntegral());
        order.setIsMyselfPick(orderNewRequest.getIsMyselfPick());
        order.setUserId(user.getId());
        order.setOrderPayType(OrderPayType.小程序);
        order.setUserId(user.getId());
        order.setIsMyselfPick(orderNewRequest.getIsMyselfPick());
        order.setOrderNo(WebUtil.noceStr());
        order.setRefundNo(WebUtil.noceStr());
        order.setOrderType(OrderType.普通订单);
        order.setFreightPrice(freightPrice);
        if (order.getIsMyselfPick() == Boolean.TRUE){
            order.setIsFreightFree(true);
        }else{
            order.setIsFreightFree(false);
        }
        //保存收货地址
        saveOrderAddress(orderNewRequest, order);
        order = orderRepository.save(order);
        //2.计算订单总金额
        List<LineItem> items = lineItemService.transformFromModel(orderNewRequest.getItems(),order);
        Order payPriceOrder = calPayPrice(order,items);
        //3.rabbit 消息队列
        //rabbit 消息队列
        expireAndDeleteOrderSender.sendCheckOrderExpiredAndDelete(payPriceOrder.getOrderNo());
        return payPriceOrder;
    }

    private Order calPayPrice(Order order,List<LineItem> items) {
        order.setOrderPayType(OrderPayType.小程序);
        BigDecimal payMoney = new BigDecimal(totalPrice(items));
        if (order.getIsFreightFree() == Boolean.FALSE){
            payMoney = payMoney.add(order.getFreightPrice()).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        order.setPayMoney(payMoney);
        return orderRepository.save(order);
    }
    private Double totalPrice(List<LineItem> items){
        Double sum = 0.0;
        for(int i = 0;i < items.size(); i++){
            LineItem lineItem = items.get(i);
            sum += lineItem.totalPrice();
        }
        return sum;
    }
    private void saveOrderAddress(OrderNewRequest orderNewRequest, Order order) {
        UserAddress address = userAddressRepository.findById(orderNewRequest.getAddressId()).orElse(null);
        OrderAddress orderAddress = new OrderAddress();
        orderAddress.setOrderId(order.getId());
        orderAddress.setProvince(address.getProvince());
        orderAddress.setCity(address.getCity());
        orderAddress.setDistrict(address.getDistrict());
        orderAddress.setStreet(address.getStreet());
        orderAddress.setPhone(address.getPhone());
        orderAddress.setName(address.getName());
        orderAddressRepository.save(orderAddress);
    }

    @Transactional
    public SortedMap<Object, Object> getPayInfo(Order order, String unionId,String ip) {
        User user = userRepository.findByUnionId(unionId);
        String openId;
        if (StringUtils.isEmpty(user.getWxMaOpenId())){
            //公众号的openId
            openId = user.getOpenId();
        }else{
            //小程序的openId
            openId = user.getWxMaOpenId();
        }
        SortedMap<Object, Object> sortedMap = buildPayRequest(order,openId, ip);
        log.info("请求微信支付数据:sortedMap={}",sortedMap);
        String requestXML = PayCommonUtil.getRequestXml(sortedMap);
        String result = WxPayUtil.httpRequest(wxPayProperty.getPayUrl(), "POST", requestXML);
        Map map = null;
        try {
            map = XMLUtil.doXMLParse(result);
        } catch (Exception e) {
            log.error("【微信小程序支付异步通知】xml转换失败{}", DateUtils.getStringDate());
            throw new RuntimeException("【微信小程序支付异步通知】xml转换失败");
        }
        log.info("微信支付请求返回数据:map={}",map);
        String returnCode = (String) map.get("return_code");
        if (!returnCode.equals("SUCCESS")){
            log.error("{}", ResultEnum.ORDER_PREPAY_ERROR.getMessage());
            throw new WechatAlipayToolException(ResultEnum.ORDER_PREPAY_ERROR);
        }
        SortedMap<Object, Object> packageP = jsSignPayInfo(map);
        return packageP;
    }

     
    public Order findOrderByOrderNo(String orderNo) {
        return orderRepository.findByOrderNo(orderNo);
    }

    @Transactional
    public void loseOrder(String orderNo) {
        Order order = orderRepository.findByOrderNo(orderNo);
        order.setLoseAt(new Date());
        order.setStatus(OrderStatus.已失效);
        order = orderRepository.save(order);
        productInventoryBack(order);
    }

    private void productInventoryBack( Order order){
        List<LineItem> items = lineItemRepository.findByOrderId(order.getId());
        for (LineItem item : items) {
            Product product = productRepository.findById(item.getProductId()).orElse(null);
            product.setInventory(product.getInventory() + item.getQuantity());
            productRepository.save(product);
        }
    }

    public SortedMap<Object, Object> buildPayRequest(Order order, String openId,String ip) {
        SortedMap<Object, Object> sortedMap = new TreeMap<Object, Object>();
        sortedMap.put("appid", wxPayProperty.getAppId());
        sortedMap.put("body",  wxPayProperty.getBody());
        sortedMap.put("mch_id", wxPayProperty.getMchId());
        sortedMap.put("nonce_str", WxPayUtil.getNonceStr());
        sortedMap.put("notify_url",wxPayProperty.getNotifyUrl());
        sortedMap.put("openid", openId);
        sortedMap.put("out_trade_no", order.getOrderNo());
        sortedMap.put("spbill_create_ip", ip);
        sortedMap.put("total_fee", String.valueOf(order.getPayMoney().setScale(2,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue()));
        sortedMap.put("trade_type",wxPayProperty.getTradeType());
        log.info("请求微信支付数据,加密前:sortedMap={}", sortedMap);
        String sign = PayCommonUtil.createSign("UTF-8", sortedMap, wxPayProperty.getMchKey());
        sortedMap.put("sign", sign);
        return sortedMap;
    }

    public SortedMap<Object, Object> jsSignPayInfo(Map map) {
        //得到prepay_id
        String prepay_id = (String) map.get("prepay_id");
        SortedMap<Object, Object> packageP = new TreeMap<Object, Object>();
        //！！！注意，这里是appId,上面是appid
        packageP.put("appId", wxPayProperty.getAppId());
        //时间戳
        packageP.put("nonceStr", System.currentTimeMillis()+"");
        //必须把package写成 "prepay_id="+prepay_id这种形式
        packageP.put("package", "prepay_id=" + prepay_id);
        //paySign加密
        packageP.put("signType", "MD5");
        packageP.put("timeStamp", (System.currentTimeMillis() / 1000) + "");
        //得到paySign
        String paySign = PayCommonUtil.createSign("UTF-8", packageP, wxPayProperty.getMchId());
        packageP.put("paySign", paySign);
        log.info("微信支付返回前端数据:packageP = {}",packageP);
        return packageP;
    }

}









